package com.hxzy.controller.admin;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.hxzy.common.dto.ExistsDTO;
import com.hxzy.common.enums.AckCode;
import com.hxzy.common.exception.ShopException;
import com.hxzy.common.util.ServletUtils;
import com.hxzy.common.vo.PageVO;
import com.hxzy.common.vo.R;
import com.hxzy.service.system.ExistsService;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.List;


/**
 * 通用控制器
 */
public class BaseController {

    /**
     * 判断表中的值是否唯一
     */
    @Autowired
    protected ExistsService  existsService;

    protected R toR(int row){
        return  row>0? R.ok():  R.build(AckCode.FAIL);
    }

    protected  R toR(boolean result){
        return  result? R.ok():  R.build(AckCode.FAIL);
    }

    /**
     * 第页第三步，把Mybatis返回的结果IPage转换自定义的对象
     * @param page
     * @return
     */
    private static final String PAGE_NUM_NAME="page";

    private static final String PAGE_SIZE_NAME="size";

    /**
     * 启动pageHelper分页 PageHelper.startPage(1, 10);
     */
    protected void startPageHelper(){
        //当前第几页
        int page= ServletUtils.getParamsToInt(PAGE_NUM_NAME);
        //每页多少笔
        int size=ServletUtils.getParamsToInt(PAGE_SIZE_NAME);

        //使用pagehelper，开启mybatis分页拦截器
        PageHelper.startPage(page,size);
    }

    /**
     * 把pageHelper返回的Page对象转换成自已定义的对象
     * @param list
     * @return
     */
    protected R  pageToPageVO(List list){
        PageVO  pageVO=new PageVO();

        //mybatis分页插件
        if(list instanceof Page){
            Page  pg= (Page) list;
            pageVO.setTotal(pg.getTotal());
            pageVO.setRows(pg.getResult());
        }else{
            //普通的list
            pageVO.setRows(list);
            pageVO.setTotal(0L);
        }
        return  R.okHasData(pageVO);
    }

    /**
     * 把list变为分页的输出结果
     * @param list
     * @return
     */
    protected R listToPageVO(List list) {
        PageVO pageVo = new PageVO();
        pageVo.setTotal(0L);
        pageVo.setRows(list);
        return R.okHasData(pageVo);
    }




    /**
     * 验证管理员数据唯一的
     * @param entity   实体类(mybatis-plus声明过)
     * @param columnName       验证数据库某个列名
     * @param columnValue      验证数据库某个列的值
     */
    protected void adminValidateExistsValue(Object entity,String columnName,String columnValue) throws IllegalAccessException {
        ExistsDTO existsDTO=new ExistsDTO();

        //反射
        Class  cls=entity.getClass();

        String className= cls.getSimpleName();

        //获取类上的注解
        Annotation tableName = cls.getDeclaredAnnotation(TableName.class);
        if(tableName==null){
            throw new ShopException(StrUtil.format("{}实体类上面注解要有@TableName注解", className));
        }
        String tableNameValue=((TableName)tableName).value();


        boolean hasTableId=false;
        //先要获取所有的字段，再判断这个字段上是否有 这个 TableId
        Field[] declaredFields = cls.getDeclaredFields();
        for(Field fi:  declaredFields){
            TableId tableIdAnnon = fi.getDeclaredAnnotation(TableId.class);
            if(tableIdAnnon!=null){
                hasTableId=true;
                String tableIdValue=tableIdAnnon.value();
                //如果注解没有 value 值
                if(StrUtil.isBlank(tableIdValue)){
                    //得到字段名
                    String fieldName= fi.getName();
                    tableIdValue= camelToUnderline( fieldName);
                }

                //开启强制访问私有变量
                fi.setAccessible(true);
                Object fiValue = fi.get(entity);
                if(fiValue!=null){
                    //主键列
                    existsDTO.setPkName(tableIdValue);
                    existsDTO.setPkValue( fiValue.toString());
                }

                break;
            }
        }

        // 如果实体类没有 @TableId主键,提示错误
        if(!hasTableId){
            throw new ShopException(StrUtil.format("{}实体类上面注解要有@TableId(value='数据库的列')注解", className));
        }



        existsDTO.setTableName( tableNameValue );



        existsDTO.setColumName(columnName);
        existsDTO.setColumnValue( columnValue );


        int count = this.existsService.existsValue(existsDTO);
        if(count>0){
            String msg= StrUtil.format(AckCode.DATA_EXISTS.getMsg(),  columnValue);
            throw new ShopException(msg);
        }
    }

    //转变的依赖字符
    private static final char UNDERLINE='_';

    /**
     * 将驼峰转换成"_"(userId 换成 user_id)
     * @param param
     * @return
     */
    public static String camelToUnderline(String param){
        if (param==null||"".equals(param.trim())){
            return "";
        }
        int len=param.length();
        StringBuilder sb=new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c=param.charAt(i);
            if (Character.isUpperCase(c)){
                sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            }else{
                sb.append(c);
            }
        }
        return sb.toString();
    }

    protected <T> void writeExcel(HttpServletResponse response, String excelName, Class<T> tClass, List<T> data) throws IOException {

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String chinaFileName=excelName+"_"+ UUID.fastUUID().toString()+".xlsx";

        String fileName = URLEncoder.encode(chinaFileName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename="+ fileName );

        //文件下载
        EasyExcel.write(response.getOutputStream(), tClass).sheet(excelName).doWrite(data );
    }
}
